Lowest common ancestor (LCA) of a binary tree

Time: O(N); Space: O(H); medium

Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree.

According to the definition of LCA on Wikipedia:

“The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).”

Example 1:

Input: root = {TreeNode} [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1

Output: {TreeNode} [3]

Explanation:

  • The LCA of nodes 5 and 1 is 3.

Example 2:

Input: root = {TreeNode} [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4

Output: {TreeNode} [5]

Explanation:

  • The LCA of nodes 5 and 4 is 5, since a node can be a descendant of itself according to the LCA definition.

Notes:

  • All of the nodes’ values will be unique.

  • p and q are different and both values will exist in the binary tree.

[13]:
class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None
[14]:
class Solution1(object):
    """
    Time: O(N)
    Space: O(H)
    """
    def lowestCommonAncestor(self, root, p, q):
        """
        :type root: TreeNode
        :type p: int
        :type q: int
        :rtype: TreeNode
        """
        # Base Case
        if root is None:
            return None

        # If either n1 or n2 matches with root's key, report
        #  the presence by returning root (Note that if a key is
        #  ancestor of other, then the ancestor key becomes LCA
        if root.val == p or root.val == q:
            return root

        # Look for keys in left and right subtrees
        left_lca = self.lowestCommonAncestor(root.left, p, q)
        right_lca = self.lowestCommonAncestor(root.right, p, q)

        # If both of the above calls return Non-NULL, then one key
        # is present in once subtree and other is present in other,
        # So this node is the LCA
        if left_lca and right_lca:
            return root

            # Otherwise check if left subtree or right subtree is LCA
        return left_lca if left_lca is not None else right_lca
[15]:
s = Solution1()

root = TreeNode(3)
root.left, root.right = TreeNode(5), TreeNode(1)
root.left.left, root.left.right = TreeNode(6), TreeNode(2)
root.right.left, root.right.right = TreeNode(0), TreeNode(8)
root.left.right.left, root.left.right.right = TreeNode(7), TreeNode(4)
p = 5
q = 1
res = s.lowestCommonAncestor(root, p, q)
assert res.val == 3

root = TreeNode(3)
root.left, root.right = TreeNode(5), TreeNode(1)
root.left.left, root.left.right = TreeNode(6), TreeNode(2)
root.right.left, root.right.right = TreeNode(0), TreeNode(8)
root.left.right.left, root.left.right.right = TreeNode(7), TreeNode(4)
p = 5
q = 4
res = s.lowestCommonAncestor(root, p, q)
assert res.val == 5